package dk;

/*  ******** Todo ********

- Only ctag add files that are cil.c files
- Check to make sure that it can actually find the app name being tested
- Add in run time to show duration of cccd application.
- 

*/

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


public class Supervisor {

	util u = new util();
	StringDistances sd = new StringDistances();
	getAllCMethods gcm = new getAllCMethods();
	
	private List<fileInfo> fileContents=new ArrayList<fileInfo>();	
	private List<dk.ctag_fileInfo>ctagfileInfoList=new ArrayList<dk.ctag_fileInfo>();
	
	// Name of the application being examined 
	private static String appName="";
	
	private final String mainPath = "../sourceFiles/";
//	private final String mainPath = "C:\\Users\\Dan\\workspace\\crestClean\\sourceFiles\\";

	private final String crestFileLocation = mainPath +"/scriptoutput/" + appName + "_copy_crestfiles/";
	private final String ctagFileLocation =  mainPath +"/scriptoutput/" + appName + "_copy_ctag_output/";
	private final String outputLocation = crestFileLocation +"output/";
	private final String methodOutputLocation = outputLocation +"methodoutput/";
	private final String reportLocation = mainPath+"Reports/";
	private final String finalReportName=appName + "_comparisionReport.csv";
	
	private final int maxLevenReportingAmount = 40; // the max leven distance value which will appear in final report

	// Should the report be created in a more readable format.
	// Turning this off is useful for system debugging
	private final boolean createReportUserFriendly =true; 
	
	
	
	
	DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
	private final Date startTime = new Date(); // time when the application began
	
	
	public static void main(String[] args) throws IOException {
/*
		appName="kraw";
		Supervisor s = new Supervisor();
		s.Run();		
*/
		
		if(args.length!=1){
			System.out.println("A single argument with the application name was expected");
		}else{
			appName = args[0];
			Supervisor s = new Supervisor();
			s.Run();		
		}
			
	}
	

	public void Run() throws IOException{
		System.out.println("Examining application: " + appName);
		
		// Create and remove the necessary folders for execution
		createFolderStructure();		
	
		fileContents = u.buildfileInfoList(crestFileLocation);
 		u.buildfileInfoContents(crestFileLocation, outputLocation,fileContents);

 		// Get all of the actual methods
 		ctagfileInfoList=gcm.getCompleteMethodList(ctagFileLocation,".c.txt");
 		createMethodFiles();
	
 		// Compare the files and create report
 		compareOutputFiles(methodOutputLocation, reportLocation); 
 		
 		System.out.println("----- Application Complete ------");
 		System.out.println(u.getTimeToRunProgram(startTime)); // Show time taken to run Java portion
 		System.out.println("See Report at: " + reportLocation + finalReportName);
 		

	}
	
	
	
	
	
	// Create the individual methods
	private void createMethodFiles(){
	
		
		for(int i=0; i<fileContents.size();i++){
			fileContents.get(i).createMethodGroups();
		}
			
		String tempOrigClass="";
		for (int c=0; c<fileContents.size(); c++){
			for (int d=0; d<fileContents.get(c).getMethodList().size(); d++){
				// Create this output file
				if(!fileContents.get(c).getMethodList().get(d).getMethodName().equals("")){
					// check to see if the item is actually a method
					if(isActualMethod(fileContents.get(c).getFileName().replace(".cil.c", ""), fileContents.get(c).getMethodList().get(d).getMethodName())){
						tempOrigClass = "" + ".." + fileContents.get(c).getMethodList().get(d).getMethodName();
						u.WriteFile(fileContents.get(c).getmodifiedFilePathNoClassName().replace("...sourcefiles.scriptoutput.", "").replace("_copy", "")+tempOrigClass+".txt", methodOutputLocation,fileContents.get(c).getModifiedFilePath()+"\n" +fileContents.get(c).getMethodList().get(d).getMethodContents().toLowerCase(), false);
					}
				}
			}
			
		}
	}
	
	// Compare all of the files in a round robin fashion
	private void compareOutputFiles(String fileLocation, String reportLocation) throws IOException{
		int totalRunCount=0;
		createReportFile();
		  
		System.out.println("File Location" + fileLocation);
		
		List<fileInfo> fileinfolist=new ArrayList<fileInfo>();
		fileinfolist = u.buildReportfileInfoList(fileLocation);
		  
		  // Now for each file in the list, compare it to all of the other files.
		  int tempListCount=0;		 
		  int totalComparisionsToBeDone= (fileinfolist.size()*(fileinfolist.size()-1))/2;

		  for(int i=0; i<fileinfolist.size();i++){
			  for (int ii = 0; ii < tempListCount; ii++) {
				  if (i!=ii){ // do not compare the same file to itself
					  System.out.println("Compare files: " + fileinfolist.get(i).getFileName() + "-" + fileinfolist.get(ii).getFileName());	
					  // now determine how the files shall be compared. 
					  
					  // Create a report.
					  totalRunCount=totalRunCount+1;
					  System.out.println(calcPercentCompleted(totalRunCount, totalComparisionsToBeDone) + "% completed  " + totalRunCount+"/" + totalComparisionsToBeDone +":" +i +"#" + ii + " " + fileLocation+fileinfolist.get(ii).getFileName());
					  compareFiles(fileLocation+fileinfolist.get(i).getFileName(),fileLocation+fileinfolist.get(ii).getFileName());
				  }
			  }
			  tempListCount=tempListCount+1; 
		  }	  
	}
	

	// Compare the two files and generate the comparision values
	private void compareFiles(String inputFile1, String inputFile2) throws IOException{
		
		final String fileContents1 = u.readDoc(inputFile1);
		final String fileContents2 = u.readDoc(inputFile2);

//		final double LevenDistance2 = -1; // Use this when you want to speed the comparision process up for testing purposes
//		final double LevenDistance2 = sd.LevenDistance3(fileContents1, fileContents2);
	
		final double levenDistance = sd.getLevenPercentVal(fileContents1, fileContents2);
		
		
		System.out.println("Leven Distance: " + levenDistance);
		
		
		final String reportInfo = u.cleanReportPath(inputFile1.replace(methodOutputLocation, ""), createReportUserFriendly) + "-" + u.cleanReportPath(inputFile2.replace(methodOutputLocation, ""),createReportUserFriendly) +"," +levenDistance+"\n";
		
		// To save space, only output files that are xxx similar
		if(levenDistance <maxLevenReportingAmount){ // limit the number of files being output to the report.
			u.WriteFile(finalReportName, reportLocation, reportInfo, true);
		}
	}
	

	
	// Create the file to output the results
	private void createReportFile(){
		System.out.println("--create report--");
		final String reportHeader = "Files,LevenDistance\n";
		
		// if the file exists clear it. The report file is overwritten each time the application is ran.
		u.WriteFile(finalReportName, reportLocation, reportHeader, false);	
	}
	
	
	// Check to see if the method being observed is an actual method
	// Todo: Make it stop scanning once the value is discovered
	private boolean isActualMethod(String className, String methodName){
		boolean retVal=false;
		for(int z=0; z<ctagfileInfoList.size();z++){
			if(ctagfileInfoList.get(z).getClassName().toLowerCase().equals(className)){
				if(ctagfileInfoList.get(z).getMethodName().toLowerCase().equals(methodName)){
					retVal=true;
				}
			}
		}
		
		return retVal;
	}
	
	
	// Create the necessary folders for output as needed
	private void createFolderStructure(){

		u.createDirIfNotExist(reportLocation);
				
		// Create the regular output directory
		 u.createAndClearDir(outputLocation);
		
		// create the methodoutput directory inside of the application
		 u.createAndClearDir(methodOutputLocation);
	}
	

	// Determine the completion rate of a comparision
	private int calcPercentCompleted(int completed, int total){
		return (int)(((double)completed/(double)total) * 100);
	}
	
	
}

